//
// Created by xsh on 2025/5/25.
//

//#include "slengine.h"
#include <SLES/OpenSlES.h>
#include <SLES/OpenSLES_Platform.h>
#include <SLES/OpenSLES_Android.h>
#include <jni.h>
#include <math.h>
#include <iostream>
#include <map>
#include <string>
#include <iomanip> // 用于控制输出精度
#include <android/log.h>/*
std::map<std::string, double> note_frequencies = {
        {"C4", 261.63},
        {"C#4", 277.18},
        {"Db4", 277.18},
        {"D4", 293.66},
        {"D#4", 311.13},
        {"Eb4", 311.13},
        {"E4", 329.63},
        {"F4", 349.23},
        {"F#4", 369.99},
        {"Gb4", 369.99},
        {"G4", 392.00},
        {"G#4", 415.30},
        {"Ab4", 415.30},
        {"A4", 440.00},
        {"A#4", 466.16},
        {"Bb4", 466.16},
        {"B4", 493.88},
        {"C5", 523.25}
};*/
//char *current_wave_type = "sin";
enum WaveType { SINE, SAWTOOTH, TRAN,SQUARE };
WaveType currenWaveType = WaveType::SINE;
const double amplitude = 0.5;
//const double sampleRate = 44100.0;
const double sampleRate = 48000.0;
const int samplesPerBuffer = 1024;
double frequency = 261.63; //默认c4 440.0
// 生成正弦波样本的缓冲区
short buffer[2][samplesPerBuffer];
int currentBuffer = 0;

SLObjectItf engineObject;
SLEngineItf engineEngine;

// 播放器
SLObjectItf playerObj;
SLPlayItf playerPlay;

SLAndroidSimpleBufferQueueItf playerBufferQueue;

// 新增前向声明
void bufferQueueCallback(SLAndroidSimpleBufferQueueItf bq, void *context);
double generateSineWave(short* outputBuffer, int numSamples,
                        double currentPhase, double freq,
                        double amp, double sRate);
double gentran(short* outputBuffer, int numSamples,double currentPhase, double freq,double amp, double sRate);
double gensaw(short* outputBuffer, int numSamples,double currentPhase, double freq,double amp, double sRate);
double gensquare(short* outputBuffer, int numSamples,double currentPhase, double freq,double amp, double sRate);

typedef struct CallbackContext {
    double currentPhase;   // 当前相位
    short* pcmBuffer;      // 音频缓冲区
} CallbackContext;
CallbackContext *ctx = nullptr;
extern "C"
JNIEXPORT void JNICALL
Java_com_xsh_opensltest_SlInstrumentTest_initEngine(JNIEnv *env, jobject thiz)
{
    // 创建引擎
    SLresult result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
    if(result !=SL_RESULT_SUCCESS)
    {
        __android_log_print(ANDROID_LOG_ERROR, "OpenSLES", "slCreateEngine failed");
    }
    SLresult engineRealize = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
    if(engineRealize !=SL_RESULT_SUCCESS)
    {
        __android_log_print(ANDROID_LOG_ERROR, "OpenSLES", "engineRealize failed");
    }
    SLresult engineInterFace = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
    if(engineInterFace !=SL_RESULT_SUCCESS)
    {
        __android_log_print(ANDROID_LOG_ERROR, "OpenSLES", "engineInterFace failed");
    }
    // 创建混音器
    SLObjectItf outputMixObject;
    SLresult outputMix = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, NULL, NULL);
    if(outputMix !=SL_RESULT_SUCCESS)
    {
        __android_log_print(ANDROID_LOG_ERROR, "OpenSLES", "CreateOutputMix failed");
    }
    SLresult outputMixRealize = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
    if(outputMixRealize !=SL_RESULT_SUCCESS)
    {
        __android_log_print(ANDROID_LOG_ERROR, "OpenSLES", "outputMixRealize failed");
    }

    // 配置音频参数
    // 定义 PCM 参数
    SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {
            SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
            2 // 缓冲区数量
    };

    SLDataFormat_PCM format_pcm = {
            SL_DATAFORMAT_PCM,
            2,                  // 声道数2 对应 SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,
            SL_SAMPLINGRATE_48, // 采样率 44100Hz
            SL_PCMSAMPLEFORMAT_FIXED_16, // 16位采样
            SL_PCMSAMPLEFORMAT_FIXED_16,
            //SL_SPEAKER_FRONT_CENTER,
            SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT,
            SL_BYTEORDER_LITTLEENDIAN
    };

    SLDataSource audioSrc = {&loc_bufq, &format_pcm};

    SLDataLocator_OutputMix loc_outmix = {
        SL_DATALOCATOR_OUTPUTMIX,
        outputMixObject
    };
    SLDataSink audioSnk = {&loc_outmix, NULL};

    const SLInterfaceID ids[1] = {SL_IID_BUFFERQUEUE};
    const SLboolean req[1] = {SL_BOOLEAN_TRUE};
    //创建播放器
    SLresult resultAudioPlayer = (*engineEngine)->CreateAudioPlayer(
        engineEngine,
        &playerObj,// 改成engineObject试试 Error:createAudioPlayer failed
        &audioSrc,
        &audioSnk,
        1, ids, req
    );
    if(resultAudioPlayer!=SL_RESULT_SUCCESS)
    {
        __android_log_print(ANDROID_LOG_ERROR, "OpenSLES", "createAudioPlayer failed");
    }
    // 可能要改下面的代码
    (*playerObj)->Realize(playerObj, SL_BOOLEAN_FALSE);
    (*playerObj)->GetInterface(playerObj, SL_IID_PLAY, &playerPlay);
    SLresult  getBufferQueueResult = (*playerObj)->GetInterface(playerObj, SL_IID_BUFFERQUEUE, &playerBufferQueue);
    if(getBufferQueueResult!=SL_RESULT_SUCCESS){
        __android_log_print(ANDROID_LOG_ERROR, "OpenSLES", "GetInterface(BUFFERQUEUE) failed: %d", getBufferQueueResult);
    }
    ctx = new CallbackContext ();
    ctx->currentPhase = 0.0;
    ctx->pcmBuffer = new short[samplesPerBuffer];// 分配缓冲区内存
    SLresult  regResult = (*playerBufferQueue)->RegisterCallback(playerBufferQueue, bufferQueueCallback, ctx);
    if(regResult!=SL_RESULT_SUCCESS)
    {
        __android_log_print(ANDROID_LOG_ERROR, "OpenSLES", "RegisterCallback failed: %d", regResult);
    }
    bufferQueueCallback(playerBufferQueue, ctx); // 第一次填充
    bufferQueueCallback(playerBufferQueue, ctx); // 第二次填充
    //SLresult playResult = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING);
    /*if (playResult != SL_RESULT_SUCCESS) {
        __android_log_print(ANDROID_LOG_ERROR, "OpenSLES", "SetPlayState failed: %d", playResult);
    }*/
}

// 缓冲队列回调函数

void bufferQueueCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
{
    CallbackContext *ctx = (CallbackContext*)context;
    if(currenWaveType == WaveType::SINE)
    {
        ctx->currentPhase = generateSineWave(ctx->pcmBuffer,samplesPerBuffer,ctx->currentPhase,frequency,amplitude,sampleRate);
    }
    else if(currenWaveType == WaveType::SAWTOOTH)
    {
        ctx->currentPhase = gensaw(ctx->pcmBuffer,samplesPerBuffer,ctx->currentPhase,frequency,amplitude,sampleRate);
    }
    else if(currenWaveType == WaveType::TRAN)
    {
        ctx->currentPhase = gentran(ctx->pcmBuffer,samplesPerBuffer,ctx->currentPhase,frequency,amplitude,sampleRate);
    }
    else if(currenWaveType == WaveType::SQUARE)
    {
        ctx->currentPhase = gensquare(ctx->pcmBuffer,sampleRate,ctx->currentPhase,frequency,amplitude,sampleRate);
    }


    SLresult  r = (*bq)->Enqueue(bq,ctx->pcmBuffer,sizeof(short)*samplesPerBuffer);
    if(r !=SL_RESULT_SUCCESS)
    {
        __android_log_print(ANDROID_LOG_ERROR,"OpenSLES","Enqueue failed: ");
        __android_log_print(ANDROID_LOG_ERROR,"OpenSLES","%d", r);
    }
}


double generateSineWave(short* outputBuffer, int numSamples,double currentPhase, double freq,double amp, double sRate) {
    const double phaseIncrement = 2.0 * M_PI * freq / sRate;

    for (int i = 0; i < numSamples; i++) {
        outputBuffer[i] = (short)(amp * 32767.0 * sin(currentPhase));
        currentPhase += phaseIncrement;

        // 相位保持在0-2π范围内，避免精度丢失
        if (currentPhase > 2 * M_PI) {
            currentPhase -= 2 * M_PI;
        }
    }
    return currentPhase;
}
double gentran(short* outputBuffer, int numSamples,double currentPhase, double freq,double amp, double sRate) {
    // 计算每个样本的相位增量
    const double phaseIncrement = 2.0 * M_PI * freq / sRate;

    for (int i = 0; i < numSamples; i++) {
        // 将相位约束在 [0, 2π) 范围内
        double phase = fmod(currentPhase, 2 * M_PI);

        // 计算三角波值（范围：-1.0 ~ 1.0）
        double value;
        if (phase < M_PI) {
            // 上升阶段：从 -1 线性增长到 1
            value = (2.0 / M_PI) * phase - 1.0;
        } else {
            // 下降阶段：从 1 线性下降到 -1
            value = 3.0 - (2.0 / M_PI) * phase;
        }

        // 将浮点值转换为 16 位有符号整数
        outputBuffer[i] = (short)(amp * 32767.0 * value);

        // 更新相位
        currentPhase += phaseIncrement;

        // 相位超过 2π 时回绕（避免浮点溢出）
        if (currentPhase >= 2 * M_PI) {
            currentPhase -= 2 * M_PI;
        }
    }

    return currentPhase; // 返回更新后的相位以保持连续性
}

double gensaw(short* outputBuffer, int numSamples,double currentPhase, double freq,double amp, double sRate)
{
    const double phaseIncrement = 2.0 * freq / sRate; // 锯齿波相位增量不同

    for (int i = 0; i < numSamples; i++) {
        // 锯齿波公式：y = 2 * (phase / (2π)) - 1
        double value = 2.0 * (currentPhase / (2 * M_PI)) - 1.0;
        outputBuffer[i] = (short)(amp * 32767.0 * value);
        currentPhase += phaseIncrement;

        // 相位保持在0-2π范围内
        if (currentPhase >= 2 * M_PI) {
            currentPhase -= 2 * M_PI;
        }
    }
    return currentPhase;
}
// 运行后卡住界面
double gensquare(short* outputBuffer, int numSamples,
                 double currentPhase, double freq,
                 double amp, double sRate) {
    // 输入参数校验
    if (outputBuffer == nullptr || numSamples <= 0 || sRate <= 0) {
        return currentPhase;
    }

    // 限制频率不超过 Nyquist 频率
    freq = fmin(freq, sRate / 2.0);
    const double phaseIncrement = 2.0 * M_PI * freq / sRate;

    for (int i = 0; i < numSamples; i++) {
        // 严格相位回绕
        currentPhase = fmod(currentPhase, 2 * M_PI);

        // 方波生成
        double value = (currentPhase < M_PI) ? 1.0 : -1.0;
        outputBuffer[i] = (short)(amp * 32767.0 * value);

        // 更新相位
        currentPhase += phaseIncrement;
    }

    // 最终相位回绕
    return fmod(currentPhase, 2 * M_PI);
}

extern "C"
JNIEXPORT void JNICALL
Java_com_xsh_opensltest_SlInstrumentTest_play(JNIEnv *env, jobject thiz)
{
    (*playerPlay)->SetPlayState(playerPlay,SL_PLAYSTATE_PLAYING);
}

// 别删除
extern "C"
JNIEXPORT jstring JNICALL
Java_com_xsh_opensltest_MyTest_mytest(JNIEnv *env, jobject thiz)
{
    const char* a = "hello from ndk";
    return env->NewStringUTF(a);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_xsh_opensltest_SlInstrumentTest_stop(JNIEnv *env, jobject thiz)
{
    (*playerPlay)->SetPlayState(playerPlay,SL_PLAYSTATE_STOPPED);
}

extern "C"
JNIEXPORT void JNICALL
Java_com_xsh_opensltest_SlInstrumentTest_changeWave(JNIEnv *env, jobject thiz,jstring type)
{
    const char* typeStr = env->GetStringUTFChars(type,nullptr);
    //__android_log_print(ANDROID_LOG_DEBUG,"currentType","%s", typeStr);
    if(strcmp(typeStr,"sin")==0)
    {
        currenWaveType = WaveType::SINE;
    }
    else if(strcmp(typeStr,"saw")==0)
    {
        currenWaveType = WaveType::SAWTOOTH;
    }
    else if(strcmp(typeStr,"tran")==0)
    {
        currenWaveType = WaveType::TRAN;
    }
    else if(strcmp(typeStr,"square")==0)
    {
        currenWaveType = WaveType::SQUARE;
    }
}

extern "C"
JNIEXPORT void JNICALL
Java_com_xsh_opensltest_SlInstrumentTest_playNote(JNIEnv *env, jobject thiz,jint note)
{
    if(note == 0)
    {
        frequency = 261.63 ;
    }
    else if(note ==1)
    {
        frequency =293.66;
    }
}
/*void load_plugin(jstring name)
{

}*/